package com.lty.nio.client;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/***
 * 
* <p>Title: NIOServer</p>
* <p>Description: NIO客户端</p>
* <p>Company: lty</p>
* @author liuhao
* @date 2017年7月5日 上午10:41:17
 */
public class NIOClient {
	//每次发送数据加标识
	private int flag = 1;
	
	//缓冲区字节大小
	private int blockSize = 4096;
	
	//发送缓冲区
	private ByteBuffer sendBuff = ByteBuffer.allocate(blockSize);
	
	//接收缓冲区
	private ByteBuffer receiveBuff = ByteBuffer.allocate(blockSize);
	
	//选择器
	private Selector selector;
	
	public NIOClient(String ip, int port) throws IOException {
		//连接服务端地址
		InetSocketAddress serverAddress = new InetSocketAddress(ip, port);
		
		//客户端开启SocketChannel
		SocketChannel socketChannel = SocketChannel.open();
		
		//设置是否阻塞
		socketChannel.configureBlocking(false);
		
		//打开选择器
		selector = Selector.open();
		
		//socketChannel向selector注册connect事件
		socketChannel.register(selector, SelectionKey.OP_CONNECT);
		socketChannel.connect(serverAddress);
		
		System.out.println("client tried to connect to server: " + ip + ":" + port);
	}

	//监听客户端连接事件
	private void connectToServer() throws IOException{
		while(true){
			selector.select();
			Set<SelectionKey> selectionKeys = selector.selectedKeys();
			Iterator<SelectionKey> iterator = selectionKeys.iterator();
			
			//遍历selector里面所有SelectionKey
			while(iterator.hasNext()){
				SelectionKey selectionKey = iterator.next();
				
				//清除key元素
				//iterator.remove();
				
				//对每个SelectionKey处理相应的IO事件
				handleKey(selectionKey);
			}
			//清除selector所有SelectionKey
			selectionKeys.clear();
 		}
	}
	
	//处理具体的key
	private void handleKey(SelectionKey selectionKey) throws IOException{
		//客户端的SocketChannel
		SocketChannel client = null;
		
		String sendText;
		String receiveText;
		int count = 0;
		
		if(selectionKey.isConnectable()){
			System.out.println("client conected!");
			
			//这里是SocketChannel
			client = (SocketChannel) selectionKey.channel();
			
			if(client.isConnectionPending()){
				//完成连接
				client.finishConnect();
				System.out.println("client conected to server!");
				sendBuff.clear();
				sendBuff.put("Hello server!".getBytes());
				sendBuff.flip();
				client.write(sendBuff);
			}
			
			//client向selector注册read事件
			client.register(selector, SelectionKey.OP_READ);
		}
		if(selectionKey.isReadable()){
			client = (SocketChannel) selectionKey.channel();
			
			//这里必须加上清空命令，否则缓冲区会保留上次读入结果
			receiveBuff.clear();
			count = client.read(receiveBuff);
			
			if(count > 0){
				receiveText = new String(receiveBuff.array(), 0, count);
				System.out.println("client received from server: " + receiveText);
				
				//client向selector注册write事件
				client.register(selector, SelectionKey.OP_WRITE);
			}
		}
		if(selectionKey.isWritable()){
			//这里必须加上清空命令，否则缓冲区会保留上次写入结果
			sendBuff.clear();
			client = (SocketChannel) selectionKey.channel();

			//要发送的文本信息
			sendText = "Hello Server!——times: " + flag++;
			sendBuff.put(sendText.getBytes());
			sendBuff.flip();
			client.write(sendBuff);
			
			System.out.println("client sent msg to server: " + sendText);
			
			//client向selector注册read事件
			client.register(selector, SelectionKey.OP_READ);
		}
	}

	public static void main(String[] args) throws IOException {
		NIOClient nioServer = new NIOClient("127.0.0.1",2017);
		nioServer.connectToServer();
	}

}
